package com.miaosmart.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.miaosmart.common.context.UserContext;
import com.miaosmart.common.convention.exception.ServiceException;
import com.miaosmart.dto.ModelDTO;
import com.miaosmart.dto.resp.CreateSessionRespDTO;
import com.miaosmart.dto.resp.GetSessionsRespDTO;
import com.miaosmart.entity.Message;
import com.miaosmart.entity.Model;
import com.miaosmart.entity.Session;
import com.miaosmart.mapper.MessageMapper;
import com.miaosmart.mapper.ModelMapper;
import com.miaosmart.mapper.SessionMapper;
import com.miaosmart.service.ChatService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.vectorstore.filter.Filter;
import org.springframework.ai.vectorstore.filter.FilterExpressionBuilder;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;

@Slf4j
@Service
@RequiredArgsConstructor
public class ChatServiceImpl implements ChatService {

    private final SessionMapper sessionMapper;
    private final ModelMapper modelMapper;
    private final MessageMapper messageMapper;


    private final ChatClient chatClient;


    private final VectorStore vectorStore;


    @Override
    @Transactional
    public CreateSessionRespDTO createSession(String title) {
        // 创建新会话
        Session session = new Session();
        session.setTitle(title);
        session.setUserId(UserContext.getUserId());

        int insert = sessionMapper.insert(session);
        if (insert <= 0) {
            throw new RuntimeException("创建会话失败");
        }

        return new CreateSessionRespDTO()
                .setId(session.getId())
                .setTitle(session.getTitle())
                .setHistory(new ArrayList<>());
    }

    @Override
    public List<GetSessionsRespDTO> getSessions() {
        // 构建查询条件
        LambdaQueryWrapper<Session> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Session::getUserId, UserContext.getUserId())
                .orderByDesc(Session::getUpdatedAt);  // 按更新时间倒序排列

        // 查询会话列表
        List<Session> sessions = sessionMapper.selectList(queryWrapper);

        // 转换为 DTO
        return sessions.stream().map(session -> {
            GetSessionsRespDTO dto = new GetSessionsRespDTO();
            dto.setId(session.getId());
            dto.setTitle(session.getTitle());
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public CreateSessionRespDTO getSession(Long sessionId) {
        // 查询会话是否存在
        Session session = sessionMapper.selectById(sessionId);
        if (session == null) {
            throw new RuntimeException("会话不存在");
        }

        // 验证是否是当前用户的会话
        if (!session.getUserId().equals(UserContext.getUserId())) {
            throw new RuntimeException("无权访问此会话");
        }

        // 查询会话的历史消息
        LambdaQueryWrapper<Message> messageWrapper = new LambdaQueryWrapper<>();
        messageWrapper.eq(Message::getSessionId, sessionId)
                .orderByAsc(Message::getCreatedAt);  // 按创建时间升序排列
        List<Message> messages = messageMapper.selectList(messageWrapper);

        // 构建返回对象
        CreateSessionRespDTO respDTO = new CreateSessionRespDTO();
        respDTO.setId(session.getId());
        respDTO.setTitle(session.getTitle());
        respDTO.setHistory(messages);

        return respDTO;
    }

    @Override
    public List<ModelDTO> getModels() {
        // 获取所有模型
        List<Model> models = modelMapper.selectList(null);

        // 转换为DTO
        return models.stream().map(model -> {
            ModelDTO dto = new ModelDTO();
            BeanUtils.copyProperties(model, dto);
            return dto;
        }).collect(Collectors.toList());
    }

    @Override
    public void switchModel(Long sessionId, ModelDTO model) {

    }

    @Override
    @Transactional
    public void updateSessionTitle(Long sessionId, String title) {
        // 查询会话是否存在
        Session session = sessionMapper.selectById(sessionId);
        if (session == null) {
            throw new RuntimeException("会话不存在");
        }

        // 验证是否是当前用户的会话
        if (!session.getUserId().equals(UserContext.getUserId())) {
            throw new RuntimeException("无权修改此会话");
        }

        // 更新标题
        Session updateSession = new Session();
        updateSession.setId(sessionId);
        updateSession.setTitle(title);

        int update = sessionMapper.updateById(updateSession);
        if (update <= 0) {
            throw new RuntimeException("更新会话标题失败");
        }
    }

    @Override
    @Transactional
    public void deleteSession(Long sessionId) {
        // 查询会话是否存在
        Session session = sessionMapper.selectById(sessionId);
        if (session == null) {
            throw new RuntimeException("会话不存在");
        }

        // 验证是否是当前用户的会话
        if (!session.getUserId().equals(UserContext.getUserId())) {
            throw new RuntimeException("无权删除此会话");
        }

        // 删除会话
        int delete = sessionMapper.deleteById(sessionId);
        if (delete <= 0) {
            throw new RuntimeException("删除会话失败");
        }

        // 删除相关的消息记录
        LambdaQueryWrapper<Message> messageWrapper = new LambdaQueryWrapper<>();
        messageWrapper.eq(Message::getSessionId, sessionId);
        messageMapper.delete(messageWrapper);
    }


    @Override
    @Transactional
    public Flux<String> streamMessage(Long sessionId, String content) {
        // 1. 验证会话是否存在
        Session session = sessionMapper.selectById(sessionId);
        if (session == null) {
            log.error("会话不存在，sessionId: {}", sessionId);
            return Flux.error(new ServiceException("会话不存在"));
        }

        // 验证是否是当前用户的会话
        if (!session.getUserId().equals(UserContext.getUserId())) {
            log.error("用户无权访问会话，userId: {}, sessionUserId: {}", UserContext.getUserId(), session.getUserId());
            return Flux.error(new ServiceException("无权访问此会话"));
        }

        // 2. 保存用户消息
        Message userMessage = new Message();
        userMessage.setSessionId(sessionId);
        userMessage.setRole("user");
        userMessage.setContent(content);
        userMessage.setCreatedAt(new Date());
        
        try {
            messageMapper.insert(userMessage);
            log.info("用户消息已保存，消息ID: {}, 会话ID: {}", userMessage.getId(), sessionId);
        } catch (Exception e) {
            log.error("保存用户消息失败", e);
            return Flux.error(new ServiceException("保存用户消息失败"));
        }

        // 3. 创建AI回复消息对象
        Message aiMessage = new Message();
        aiMessage.setSessionId(sessionId);
        aiMessage.setRole("ai");
        aiMessage.setCreatedAt(new Date());
        aiMessage.setContent(""); // 初始为空，后续会更新

        // 4. 先插入AI消息记录，获取ID
        try {
            messageMapper.insert(aiMessage);
            log.info("AI消息记录已创建，消息ID: {}, 会话ID: {}", aiMessage.getId(), sessionId);
        } catch (Exception e) {
            log.error("创建AI消息记录失败", e);
            return Flux.error(new ServiceException("创建AI消息记录失败"));
        }

        Long aiMessageId = aiMessage.getId();

        // 5. 定义一个可变变量用于收集流数据
        AtomicReference<StringBuilder> contentCollector = new AtomicReference<>(new StringBuilder());

        // 6. 创建会话特定的RAG顾问，只检索当前会话的文档
        Filter.Expression sessionFilter = new FilterExpressionBuilder()
                .eq("sessionId", sessionId.toString())
                .build();
        
        QuestionAnswerAdvisor sessionSpecificAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
                .searchRequest(SearchRequest.builder()
                        .filterExpression(sessionFilter)
                        .build())
                .build();

        // 7. 调用 AI 服务获取流式响应
        return chatClient.prompt()
                .user(content)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId))
                .advisors(sessionSpecificAdvisor)
                .stream()
                .content()
                .retry(5) // 增加重试次数
                .timeout(Duration.ofSeconds(60)) // 增加超时时间
                .doOnNext(chunk -> {
                    // 实时收集内容
                    if (chunk != null) {
                        contentCollector.get().append(chunk);
                    }
                })
                .doOnError(e -> {
                    log.error("流式调用出错，sessionId: {}, aiMessageId: {}", sessionId, aiMessageId, e);
                    // 出错时保存错误信息到数据库
                    try {
                        aiMessage.setContent("Error: " + e.getMessage());
                        messageMapper.updateById(aiMessage);
                        log.info("错误信息已保存到数据库，消息ID: {}", aiMessageId);
                    } catch (Exception dbError) {
                        log.error("保存错误信息到数据库失败", dbError);
                    }
                })
                .doOnComplete(() -> {
                    // 流完成时保存完整的AI回复到数据库
                    try {
                        String completeContent = contentCollector.get().toString();
                        if (!completeContent.isEmpty()) {
                            aiMessage.setContent(completeContent);
                            messageMapper.updateById(aiMessage);
                            log.info("AI回复已保存到数据库，消息ID: {}, 内容长度: {}, 会话ID: {}", 
                                    aiMessageId, completeContent.length(), sessionId);
                        } else {
                            log.warn("AI回复内容为空，消息ID: {}, 会话ID: {}", aiMessageId, sessionId);
                        }
                    } catch (Exception e) {
                        log.error("保存AI回复到数据库时出错，消息ID: {}, 会话ID: {}", aiMessageId, sessionId, e);
                    }
                })
                .onErrorResume(e -> {
                    // 出错时返回错误信息
                    log.error("AI服务调用失败，sessionId: {}", sessionId, e);
                    return Flux.just("抱歉，AI服务暂时不可用，请稍后重试。");
                });
    }

    @Override
    @Transactional
    public void saveFileMessage(Long sessionId, String fileName, String fileUrl) {
        // 1. 验证会话是否存在
        Session session = sessionMapper.selectById(sessionId);
        if (session == null) {
            log.error("会话不存在，sessionId: {}", sessionId);
            throw new ServiceException("会话不存在");
        }

        // 验证是否是当前用户的会话
        if (!session.getUserId().equals(UserContext.getUserId())) {
            log.error("用户无权访问会话，userId: {}, sessionUserId: {}", UserContext.getUserId(), session.getUserId());
            throw new ServiceException("无权访问此会话");
        }

        // 2. 保存文件消息
        Message fileMessage = new Message();
        fileMessage.setSessionId(sessionId);
        fileMessage.setRole("user");
        fileMessage.setContent(""); // 文件消息内容为空
        fileMessage.setFileName(fileName);
        fileMessage.setFileUrl(fileUrl);
        fileMessage.setCreatedAt(new Date());
        
        try {
            messageMapper.insert(fileMessage);
            log.info("文件消息已保存，消息ID: {}, 会话ID: {}, 文件名: {}", fileMessage.getId(), sessionId, fileName);
        } catch (Exception e) {
            log.error("保存文件消息失败", e);
            throw new ServiceException("保存文件消息失败");
        }
    }



}
